package com.ease.web.webwork;

import java.io.StringWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.ease.web.xwork.AjaxJsonAction;
import com.ease.web.xwork.AjaxUpdaterAction;
import com.ease.web.xwork.AjaxXmlAction;
import com.opensymphony.webwork.ServletActionContext;
import com.opensymphony.xwork.ActionInvocation;
import com.opensymphony.xwork.interceptor.Interceptor;

/**
 * 
 * @author nathanleewei
 * 
 */
public class ExceptionInterceptor implements Interceptor {

	/**
	 *
	 */
	private static final long serialVersionUID = 905605379114410201L;

	private static final Log log = LogFactory.getLog(ExceptionInterceptor.class);

	public static final String EXCEPTION = "exception";

	public static final String EXCEPTION_MESSAGE = "_exception_message_";

	public static final String EXCEPTION_STACK_TRACE = "_exception_stack_trace_";

	public static final String REQEUST_STRING = "_reqeust_string_";

	private Map<Class<?>, String> exceptionTypeMap;

	/**
	 * Set the mappings between exception class names and result names.
	 * 
	 * @param mappings
	 *            fully qualified exception class names as keys, and result names as values
	 */
	public void setExceptionMappings(Properties mappings) throws ClassNotFoundException {
		this.exceptionTypeMap = new HashMap<Class<?>, String>();

		for (Iterator<?> it = mappings.keySet().iterator(); it.hasNext();) {
			String exceptionClassName = (String) it.next();
			String viewName = mappings.getProperty(exceptionClassName);
			Class<?> exceptionClass = Class.forName(exceptionClassName, true, Thread.currentThread().getContextClassLoader());
			this.exceptionTypeMap.put(exceptionClass, viewName);
		}
	}

	public String checkExceptionType(Exception e) {
		String result = null;
		if (null != this.exceptionTypeMap) {
			for (Iterator<?> it = this.exceptionTypeMap.keySet().iterator(); it.hasNext();) {
				Class<?> exceptionType = (Class<?>) it.next();
				if (exceptionType.isInstance(e)) {
					result = (String) this.exceptionTypeMap.get(exceptionType);
				}
			}
		}
		if (null == result || "".equals(result)) {
			result = EXCEPTION;
		}
		return result;
	}

	/**
	 * Invoke action and if an exception occurs, route it to the mapped result.
	 */
	public String intercept(ActionInvocation invocation) throws Exception {
		String result = null;

		try {
			result = invocation.invoke();
		} catch (Throwable e) {
			log.error(e);
			e.printStackTrace();
			//
			result = EXCEPTION;
			//
			StringWriter writer = new StringWriter();
			e.printStackTrace(new java.io.PrintWriter(writer));
			ServletActionContext.getRequest().setAttribute(EXCEPTION_STACK_TRACE, writer.toString());
			ServletActionContext.getRequest().setAttribute(EXCEPTION_MESSAGE, e.getMessage());
			ServletActionContext.getRequest().setAttribute(REQEUST_STRING, RequestUtil.getRequestString());
			writer = null;
			Object action = invocation.getAction();
			if (action instanceof AjaxJsonAction) {
				return "exception.json";
			} else if (action instanceof AjaxXmlAction) {
				return "exception.xml";
			} else if (action instanceof AjaxUpdaterAction) {
				return "exception.updater";
			}
		}
		return result;

	}

	public void destroy() {
	}

	public void init() {
	}
}